package com.example.mallcart.service.impl;

import com.common.utils.R;
import com.common.vo.MemberVO;
import com.example.mallcart.config.MgHandlerInterceptor;
import com.example.mallcart.controller.vo.CartItem;
import com.example.mallcart.controller.vo.SkuInfoVO;
import com.example.mallcart.entity.Cart;
import com.example.mallcart.fegin.ProductFeignService;
import com.example.mallcart.service.CartService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author guanglin.ma
 * @date 2024-01-07 9:21
 */
@Service
public class CartServiceImpl implements CartService {

    static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10,
            10, TimeUnit.SECONDS, new LinkedBlockingQueue(100),
            Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ProductFeignService productFeignService;
    ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 把商品添加到购物车中
     *
     * @param skuId
     * @param num
     * @return
     */
    @Override
    public CartItem addCart(String skuId, String num) throws Exception {
        BoundHashOperations<String, Object, Object> hashOperations = getCartKeyOperation();
        // 如果Redis存储在商品的信息，那么我们只需要修改商品的数量就可以了
        Object o = hashOperations.get(skuId.toString());
        if (o != null) {
            // 说明已经存在了这个商品那么修改商品的数量即可
            String json = (String) o;
            CartItem item = objectMapper.readValue(json, CartItem.class);
            item.setCount(item.getCount() + new Integer(num));
            hashOperations.put(skuId.toString(), objectMapper.writeValueAsString(item));
            return item;
        }
        CartItem item = new CartItem();
        CompletableFuture future1 = CompletableFuture.runAsync(() -> {
            // 1.远程调用获取 商品信息
            R r = productFeignService.info(new Long(skuId));
            String skuInfoJSON = null;
            try {
                skuInfoJSON = objectMapper.writeValueAsString(r.get("skuInfo"));
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
            SkuInfoVO vo = null;
            try {
                vo = objectMapper.readValue(skuInfoJSON, SkuInfoVO.class);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            item.setCheck(true);
            item.setCount(new Integer(num));
            item.setPrice(vo.getPrice());
            item.setImage(vo.getSkuDefaultImg());
            item.setSkuId(new Long(skuId));
            item.setTitle(vo.getSkuTitle());
            item.setSpuId(vo.getSpuId());
        }, threadPoolExecutor);

        CompletableFuture future2 = CompletableFuture.runAsync(() -> {
            // 2.获取商品的销售属性
            List<String> skuSaleAttrs = productFeignService.getSaleAttrs(new Long(skuId));
            item.setSkuAttr(skuSaleAttrs);
        }, threadPoolExecutor);

        CompletableFuture.allOf(future1, future2).get();
        // 3.把数据存储在Redis
        String json = objectMapper.writeValueAsString(item);
        hashOperations.put(skuId, json);

        return item;
    }


    @Override
    public Cart getCartList() throws IOException {
        BoundHashOperations<String, Object, Object> boundHashOperations = getCartKeyOperation();
        Cart cart = new Cart();
        List<CartItem> cartList = new ArrayList<>();
        String keys = boundHashOperations.getKey();
        Set<Object> objectKeys = redisTemplate.opsForHash().keys(keys);
        for (Object key : objectKeys) {
            String k = (String) key;
            Object o = redisTemplate.opsForHash().get(keys, k);
            String json = (String) o;
            CartItem cartItem = objectMapper.readValue(json, CartItem.class);
            cartList.add(cartItem);
        }
        cart.setItems(cartList);
        return cart;
    }

    BoundHashOperations<String, Object, Object> getCartKeyOperation() {
        MemberVO memberVO = MgHandlerInterceptor.threadLocal.get();
        String key = "mgmall:cart:" + memberVO.getId();
        BoundHashOperations<String, Object, Object> boundHashOperations = redisTemplate.boundHashOps(key);
        return boundHashOperations;
    }

    /**
     * 获取当前用户购物车中的商品
     *
     * @return
     */
    @Override
    public List<CartItem> getUserCartItems() throws IOException {
        BoundHashOperations<String, Object, Object> boundHashOperations = getCartKeyOperation();
        List<CartItem> cartList = new ArrayList<>();
        String keys = boundHashOperations.getKey();
        Set<Object> objectKeys = redisTemplate.opsForHash().keys(keys);
        if (!CollectionUtils.isEmpty(objectKeys)) {
            cartList = objectKeys.stream().map(object -> {
                String k = (String) object;
                Object o = redisTemplate.opsForHash().get(keys, k);
                String json = (String) o;
                CartItem cartItem = null;
                try {
                    cartItem = objectMapper.readValue(json, CartItem.class);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                return cartItem;
            }).filter(cartItem -> cartItem.isCheck()).collect(Collectors.toList());
        }
        return cartList;
    }
}
